package com.example.ipccore;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import com.example.ipccore.request.RequestBean;
import com.example.ipccore.request.RequestParameter;
import com.google.gson.Gson;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ServiceManager {
    private static final ServiceManager ourInstance = new ServiceManager();
    CacheCenter cacheCenter=CacheCenter.getInstance();
    public static ServiceManager getDefault(){
        return ourInstance;
    }
    ITuyaBinderInterface tuyaBinderInterface;
    private Context mContext;

    public void open(Context context){
        open(context,null);
    }

    private void open(Context context, String packageName) {
        mContext=context.getApplicationContext();
        bind(context.getApplicationContext(),packageName,TuYaService.class);
    }

    private void bind(Context applicationContext, String packageName, Class<? extends TuYaService> service) {
        Intent intent;
        TuyaServiceConnection tuyaServiceConnection = new TuyaServiceConnection();
        if (TextUtils.isEmpty(packageName)) {
            intent = new Intent(applicationContext, service);
        }else {
            ComponentName componentName = new ComponentName(packageName, service.getName());
            intent=new Intent();
            intent.setComponent(componentName);
            intent.setAction(service.getName());
        }
        applicationContext.bindService(intent,tuyaServiceConnection,Context.BIND_AUTO_CREATE);
    }

    public <T>T getInstance(Class<T> clazz,Object... parameters) {
        //服务发现：实际上是把需要调用的服务，以JSON的形式发送过去
        sendRequest(clazz,null,parameters, TuYaService.TYPE_GET);
        //发送请求后没有实例对象返回
        //通过动态代理实现
        return getProxy(clazz);
    }

    private <T> T getProxy(Class<T> clazz) {
        ClassLoader classLoader = mContext.getClassLoader();
        /**
         *  public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
         *   loader:classLoader
         *   interfaces：我们启动的服务实例，它所对外暴露的接口。如UserManager的对外接口是IUserManager
         *   InvocationHandler:代理处理器，Proxy.newProxyInstance返回对象后，
         *   我们会通过该对象内部方法，之后会进入到InvocationHandler内部中。
         *   这个InvocationHandler在Binder中叫做BPBinder。
         */
        return (T) Proxy.newProxyInstance(classLoader,new Class[]{clazz},new BPBinder(clazz));
    }

    Gson gson=new Gson();
    //服务发现 type=1；服务调用 type=2。
    public <T> String sendRequest(Class<T> clazz, Method method, Object[] parameters,int type) {
        RequestBean requestBean = new RequestBean();
        requestBean.setType(type);
        if (parameters!=null && parameters.length>0){
            RequestParameter[] requestParameters = new RequestParameter[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                Object parameter = parameters[i];
                String parameterClassName = parameter.getClass().getName();
                String parameterValue=gson.toJson(parameter);
                RequestParameter requestParameter = new RequestParameter(parameterClassName, parameterValue);
                requestParameters[i]=requestParameter;
            }
            requestBean.setRequestParameters(requestParameters);
        }
        String className = clazz.getAnnotation(ClassId.class).value();
        String methodName = method==null?"getInstance":method.getName();
        requestBean.setClassName(className);
        requestBean.setMethodName(methodName);
        String request = gson.toJson(requestBean);
        //通过 copy_from_user 拷贝到物理内存。
        // 再通过mmap函数，将数据传递到Service。
        //当前函数执行在SecondActivity所在的F进程，但是执行transact函数会调用主进程的Service，
        // 所以此时transact在主进程
        try {
            Log.e("xunyou", "sendRequest-发送数据："+request);
            String result = tuyaBinderInterface.transact(request);
            Log.e("xunyou", "sendRequest: 返回结果："+result);
            return result;
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
    }
    private class TuyaServiceConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("xunyou", "onServiceConnected: ");
            tuyaBinderInterface = ITuyaBinderInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }


    //服务注册
    public void add(String key,Class<?> clazz){
        cacheCenter.register(key,clazz);
    }

}
